// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Simple way to run this client:
// GLOG_v=0 GLOG_logtostderr=1 \
//   out/Default/simple_client --solver_address=localhost --tcp_port=10000 \
//   --query="array mem[10]:w32->w8 = symbolic
// (query [(Eq w8 (Read w8 0 mem) 1) (Eq w8 (Read w8 5 mem) 2)] false [] [mem])"


#include <signal.h>

#include "glog/logging.h"
#include "llvm/Support/CommandLine.h"

#include "proto/seven_summits.pb.h"
#include "stub-inl.h"

using seven_summits::SmtRequest;
using seven_summits::SmtResponse;
using seven_summits::Stub;

namespace {

llvm::cl::opt<std::string> clSolverAddress(
    "solver_address",
    llvm::cl::desc("host name of the server"),
    llvm::cl::init(""));

llvm::cl::opt<int> clTcpPort(
    "tcp_port",
    llvm::cl::desc("TCP port number to listen on"),
    llvm::cl::value_desc("port"),
    llvm::cl::init(-1));

llvm::cl::opt<std::string> clQuery(
    "query",
    llvm::cl::desc("if non-empty, query to send"),
    llvm::cl::value_desc("kquery exp"),
    llvm::cl::init("array mem[3]: w32 -> w8 = symbolic\n"
                    "(query [(Eq w8 (Read w8 0 mem) 10)] false [(w8 0)] [])"));

llvm::cl::opt<int> clTimes(
    "times",
    llvm::cl::desc("how often to send this query"),
    llvm::cl::value_desc("number"),
    llvm::cl::init(1));

}  // anonymous namespace

void sigpipe_handler(int signum) {
  VLOG(0) << "Received SIGPIPE.";
  exit(-1);
}

// TODO(bqe): implement unix domain socket
int main(int argc, char *argv[]) {
  google::InitGoogleLogging(argv[0]);
  llvm::cl::ParseCommandLineOptions(argc, argv);
  signal(SIGPIPE, sigpipe_handler);

  Stub<SmtRequest, SmtResponse>* stub =
      Stub<SmtRequest, SmtResponse>::CreateFromTcpHostPort(clSolverAddress,
                                                           clTcpPort);
  stub->Connect();
  SmtRequest request;
  SmtResponse response;
  request.set_query(clQuery);
  for (int i = 0; i < clTimes; ++i) {
    VLOG(0) << "sending request " << i;

    if (!stub->Query(request, &response)) {
      VLOG(0) << "could not send request";
      break;
    }
    VLOG(0) << "received response\n" << response.DebugString();
  } 
  stub->HangUp();
  delete stub;

  return 0;
}
